package cc.cary.warehouse.filter;


import cc.cary.warehouse.untils.Beans;
import org.springframework.util.StreamUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 解决请求body无法重复读取问题
 *
 * @author Cary
 * @date 2023/1/16
 */
public class BodyCacheRequestWrapper extends HttpServletRequestWrapper {
    private byte[] body;
    private BufferedReader reader;

    public boolean isCache() {
        return isCache;
    }

    private boolean isCache = false;

    public BodyCacheRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        String contentType = request.getHeader("Content-Type");


        isCache = "GET".equals(request.getMethod()) ||
                // 仅仅缓存JSON格式
                (Beans.strNotEmpty(contentType) && contentType.contains("application/json")) ||
                // api x-www-form-urlencoded 的请求
                (Beans.strNotEmpty(contentType) && request.getRequestURI().startsWith("/api") && contentType.contains("application/x-www-form-urlencoded"));
        if (isCache) {
            loadBody(request);
        }
    }

    private void loadBody(HttpServletRequest request) throws IOException {
        body = StreamUtils.copyToByteArray(request.getInputStream());
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (isCache) {
            return new RequestCachingInputStream(body);
        }
        return super.getInputStream();
    }

    @Override
    public BufferedReader getReader() throws IOException {
        if (isCache) {
            if (reader == null) {
                ServletInputStream inputStream = new RequestCachingInputStream(body);
                reader = new BufferedReader(new InputStreamReader(inputStream, getCharacterEncoding()));
            }
            return reader;
        } else {
            return super.getReader();
        }
    }

    private static class RequestCachingInputStream extends ServletInputStream {

        private final ByteArrayInputStream inputStream;

        public RequestCachingInputStream(byte[] bytes) {
            inputStream = new ByteArrayInputStream(bytes);
        }

        @Override
        public int read() throws IOException {
            return inputStream.read();
        }

        @Override
        public boolean isFinished() {
            return inputStream.available() == 0;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener readlistener) {
        }

    }

}